/*************************************************************************  
 *   This file is part of UBBMPSREADER.
 *
 *   UBBMPSREADER is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   UBBMPSREADER is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with UBBMPSREADER.  If not, see <http://www.gnu.org/licenses/>. 
 *************************************************************************/

package cs.ubbcluj.ro.datatypes.implementations;

import java.util.ArrayList;
import cs.ubbcluj.ro.datatypes.interfaces.*;

public strictfp class SparseMatrix extends AbstractMatrix {
    ArrayList<Integer> rowIndexes;		// sor
    ArrayList<Integer> columnIndexes;	// oszlop
    ArrayList<Double> data;				// adat
    int nrRows;							// sorsz
    int nrColumns;						// oszlopsz
    int nrData;							// elemsz

    public SparseMatrix(final int n, final int m) {
    	this.rowIndexes = new ArrayList<Integer>();
		this.columnIndexes = new ArrayList<Integer>();
		this.data = new ArrayList<Double>();
		this.nrRows = n;
		this.nrColumns = m;
		this.nrData = 0;		
    }
    
    public SparseMatrix createHelperMatrix(int n, int m) {
    	return new SparseMatrix(n, m);
    }
    
    public int getNrOfRows() {
    	return this.nrRows;
    }

    public int getNrOfColumns() {
    	return this.nrColumns;
    }
    
    public int getNrOfNonZeros() {	// size()
    	return this.nrData;
    }    
    
    public double get(final int rowIndex, final int columnIndex) {
    	double value = 0;
    	for (int i = 0; i < getNrOfNonZeros(); i++) {
    		if ((rowIndex(i) == rowIndex) && (columnIndex(i) == columnIndex))
    			value = this.data.get(i);
    	}
    	return value;
    }   
    
    public void set(final int rowIndex, final int columnIndex, final double value)
    throws InterruptedException {
	if ((rowIndex < this.nrRows) && (columnIndex < this.nrColumns)) {
	    if (value != 0) {
			this.rowIndexes.add(Integer.valueOf(rowIndex));
			this.columnIndexes.add(Integer.valueOf(columnIndex));
			this.data.add(Double.valueOf(value));
			this.nrData++;
	    }
	} else
	    throw new InterruptedException("The size of the sparseMatrix is too small ("
		    + this.nrRows + "," + this.nrColumns + ")");
    }

    public void addElement(final int rowIndex, final int columnIndex, final double value) {	// newValue(...)
		boolean isAdded = false;
		
		if (rowIndex >= nrRows)
			nrRows = rowIndex + 1;
		if (columnIndex >= nrColumns)
			nrColumns = columnIndex + 1;
		
		for (int i = 0; i < getNrOfNonZeros(); i++)
		    if ((rowIndex(i) == rowIndex) && (columnIndex(i) == columnIndex)) {
			if (value != 0) {
			    this.data.set(i, Double.valueOf(value));
			} else {
			    this.nrData--;
			    this.data.remove(i);
			    this.rowIndexes.remove(i);
			    this.columnIndexes.remove(i);
			}
			isAdded = true;
		    }
		if (!isAdded)
		    try {
		    	set(rowIndex, columnIndex, value);
		    } catch (final InterruptedException e) {
		    	System.out.println(e);
		    	System.exit(1);
		    }
    }

    public double value(final int valueIndex) {
    	return this.data.get(valueIndex);
    }

    public int rowIndex(final int i) {
    	return this.rowIndexes.get(i);
    }

    public int columnIndex(final int i) {
    	return this.columnIndexes.get(i);
    }

    public Matrix trans() throws InterruptedException {
	final Matrix transposedMatrix = new SparseMatrix(getNrOfColumns(), getNrOfRows());
	if (this.nrData > 0) {
	    for (int i = 0; i < getNrOfColumns(); i++)
		for (int j = 0; j < getNrOfNonZeros(); j++)
		    if (columnIndex(j) == i) {
		    	transposedMatrix.addElement(columnIndex(j), rowIndex(j), value(j));
		    }
	}
	return transposedMatrix;
    }

    public Matrix deleteRow(int index) {
		for (int i = getNrOfNonZeros()-1; i>=0; i--){
		    if ((rowIndex(i) == index)) {
		    	this.nrData--;
			    this.data.remove(i);
			    this.rowIndexes.remove(i);
			    this.columnIndexes.remove(i);
			    
		    }
		    if (rowIndex(i) > index){
		    	this.rowIndexes.set(i,this.rowIndexes.get(i)-1);
		    }
			
		}
		nrRows--;
		for (int i = 0; i < getNrOfColumns(); i++){
			for (int j = 0; j < getNrOfNonZeros(); j++){
				System.out.println(get(i,j)+"   ");
			}
			System.out.println();
		}
		return this;
	}

	@Override
	public void setZeroElement(int row, int column) {
		// TODO Auto-generated method stub
		
	}
}